#pragma once
#include "Comm.h"
#include "Atom.h"
#include "Buffer.h"
#if (COMM_FEATURE_LIBEVENT==1)

namespace COMM
{
	class COMM_API SocketAddress
	{
	public:
		SocketAddress(int port=0, const char* ip = NULL);
#ifdef __GNUC__
		SocketAddress(const char* unix_path);
#endif
		SocketAddress(sockaddr *sa, int socklen);
		operator sockaddr*() const;
		int Size() const;
		int Port() const;
		int Family() const;
		String ToString(bool include_port=true) const;
	private:
		union{
			sockaddr_in addr_in;
#ifdef __GNUC__
			sockaddr_un addr_un;
#endif
		}m_addr;
		int m_family;
	};

	class COMM_API SocketClient
	{
	public:
		class Guard
		{
		private:
			SocketClient* m_client;
		public:
			Guard(SocketClient* client) :m_client(client) { if (NULL != m_client) { m_client->AddRef(); } }
			~Guard() { if (NULL != m_client) { m_client->Release(); } }
		};
		enum ConnectionState{CONN_INIT=0,CONN_OPEN,CONN_EOF,CONN_ERR,CONN_SHUTDOWN,CONN_CLOSE};
		void* m_inst_opaque;
		AtomInt m_ref_count;
		SocketClient();
		virtual ~SocketClient();
		void Release();
		void AddRef();
		ConnectionState State() const;
		const SocketAddress& Address() const;
		bool AsClient() const;
		bool Write(const void* buffer, int size);
		void Close();
		
		virtual void OnOpen(){}
		// reason: CONN_EOF(peer shutdown),CONN_ERR(connection error),CONN_SHUTDOWN(close by manual).
		/*can not be blocked.*/
		virtual void OnClose(ConnectionState reason){}
		virtual void OnRead(const char* buffer, int size){}	
	};

	class COMM_API SocketClientFactory
	{
	public:
		virtual ~SocketClientFactory() {}
		virtual void Release(){ delete this;}
		virtual SocketClient* Create() = 0;
	};

	template<class CLIENT>
	class CommClientFactory : public SocketClientFactory
	{
	public:
		virtual SocketClient* Create(){ return new CLIENT;}
	};
 

	class COMM_API SocketAcceptor
	{
		MYLIB_NONCOPIED_CLASS(SocketAcceptor);
	public:
		SocketAcceptor(const SocketAddress& listenAddress, SocketClientFactory* factory,
			const char* crtfile=NULL, const char* keyfile=NULL);
		~SocketAcceptor();
		const SocketAddress& Address() const;
	private:
		void* m_inst;
	};

	class COMM_API SocketConnector
	{
		MYLIB_NONCOPIED_CLASS(SocketConnector);
	public:	
		SocketConnector(const SocketAddress& serverAddress, SocketClient* client);
		~SocketConnector();
		SocketClient* get() const;
	private:
		void* m_inst;
	};

}

#endif
